#ifndef PLINTH_DISPATCH_H
#define PLINTH_DISPATCH_H

#include "../core/AbstractObject.h"
#include "../core/ObjectFactory.h"
#include "../core/Core.h"
#include <map>

class DispatchTarget
{
public:
	virtual void recMessage(const std::string& targetName, IData& msg)=0;
};

class AccumulatorDT : public DispatchTarget
{
private:
	std::vector<std::string>* targetNameList;
	std::vector<IData>* msgList;
public:
	AccumulatorDT()
	{
		targetNameList = new std::vector<std::string>;
		msgList = new std::vector<IData>;
	}

	void recMessage(const std::string& targetName, IData& msg)
	{
		// we should do thread locking stuff here...
		targetNameList->push_back(targetName);
		msgList->push_back(msg);
	}

	void getLists(std::vector<std::string>*& names, std::vector<IData>*& msgs)
	{
		// we should do thread locking stuff here as well...
		names = targetNameList;
		msgs = msgList;
		targetNameList = new std::vector<std::string>;
		msgList = new std::vector<IData>;
	}
};

class DispatchGO : public GlobalObject
{
public:
	// Dispatch specific stuff
	void sendMessage(const std::string& target, IData& msg);
	void addTarget(DispatchTarget* tg, std::string& targetAlias);
	void removeAlias(const std::string& alias, DispatchTarget* tg); // removes just one alias
	void removeTarget(DispatchTarget* tg); // removes all references to a target

	// General global object stuff
	std::string getClassName();
	void updateFromUM(double dt);
private:
	std::map<std::string, std::vector<DispatchTarget*> > _targetMap;
	//std::vector<std::string> _targetNamesList;
	//std::vector<DispatchTarget*> _targetList;
};

//OBJTYPE Dispatch

// these tell liautogen.py how to deal with IData types
//PUSH_FUNC IData
//pushIData(L, ret);

//PUSH_FUNC IData&
//pushIData(L, ret);

//POP_FUNC IData&
//IData a%(argPos)d = popIData(L, %(luaPos)d);

//POP_FUNC IData
//IData a%(argPos)d = popIData(L, %(luaPos)d);

class Dispatch : public AbstractObject
{
public:
	Dispatch();

	// Dispatch specific stuff
	//LIAG_THESE
	void sendMessage(std::string& target, IData& msg);
	void addHandler(std::string& recName, AnyAOPtr obj);
	void addNamedHandler(std::string& recName, std::string& hName, AnyAOPtr obj);
	void removeHandler(std::string& recName);
	//STOP_LIAG

	// General abstract object stuff goes below

	// Return the c++ type id
	virtual int getCppTypeId();
	// Returns whether this can be cast to a given type
	virtual bool isType(int id);

	// Return the c++ type as a string 
	virtual std::string getCppTypeName();

	// returns a description of this thing
	virtual std::string getDescription();

	// create another one of these
	virtual AbstractObject* newInstance();

	// init & update
	virtual void init();
	virtual void update(double dt);

	// push its static functions into the given lua table
	virtual void pushStaticFuncs(lua_State* L);

	virtual ~Dispatch();
private:
	void getDGO();
	AccumulatorDT* _sink;
	DispatchGO* _dgo;
	std::map<std::string, std::pair<AnyAOPtr,std::string> > _handlerMap;
};

extern RegisterCppObj<Dispatch> g_register_dispatch_object;

#endif
